#include <nds.h>
#include <string.h>
#include <ctype.h>
#include "unicode.h"

#define ONE_BYTE_MASK 0x80
#define ONE_BYTE_SIGN 0x00
#define TWO_BYTE_MASK 0xc0e0
#define TWO_BYTE_SIGN 0x80c0
#define THREE_BYTE_MASK 0xc0c0f0
#define THREE_BYTE_SIGN 0x8080e0
#define FIRST_BYTE 0xff
#define SECOND_BYTE 0xff00
#define THIRD_BYTE 0xff0000

bool _FAT_unicode_is_unicode(const u8* src)
{
  bool res=false;
  while(*src)
  {
    u32 data=src[0],len=1;
    if((data&ONE_BYTE_MASK)==ONE_BYTE_SIGN)
    {
    }
    else
    {
      data+=src[1]*0x100;
      if((data&TWO_BYTE_MASK)==TWO_BYTE_SIGN)
      {
        res=true;
        len=2;
      }
      else
      {
        data+=src[2]*0x10000;
        if((data&THREE_BYTE_MASK)==THREE_BYTE_SIGN)
        {
          res=true;
          len=3;
        }
        else
        {
          res=false;
          break;
        }
      }
    }
    src+=len;
  }
  return res;
}

void _FAT_unicode_local_to_unicode( const u8 * src, UNICHAR * dest )
{
  while(*src)
  {
    u32 data=src[0],len=1,res='?';
    if((data&ONE_BYTE_MASK)==ONE_BYTE_SIGN)
    {
      res=data;
    }
    else
    {
      data+=src[1]*0x100;
      if((data&TWO_BYTE_MASK)==TWO_BYTE_SIGN)
      {
        res=data&~TWO_BYTE_MASK;
        res=((res&SECOND_BYTE)>>8)|((res&FIRST_BYTE)<<6);
        len=2;
      }
      else
      {
        data+=src[2]*0x10000;
        if((data&THREE_BYTE_MASK)==THREE_BYTE_SIGN)
        {
          res=data&~THREE_BYTE_MASK;
          res=((res&FIRST_BYTE)<<12)|((res&SECOND_BYTE)>>2)|((res&THIRD_BYTE)>>16);
          len=3;
        }
      }
    }
    src+=len;
    *dest++=res;
  }
  *dest=0;
}

void _FAT_unicode_unicode_to_local( const UNICHAR * src, u8 * dest )
{
  while(*src)
  {
    u16 data=*src++;
    if(data<0x80)
    {
      *dest++=data;
    }
    else if(data<0x800)
    {
      *dest++=0xc0|((data>>6)&0x1f);
      *dest++=0x80|(data&0x3f);
    }
    else
    {
      *dest++=0xe0|((data>>12)&0x0f);
      *dest++=0x80|((data>>6)&0x3f);
      *dest++=0x80|(data&0x3f);
    }
  }
  *dest=0;
}

u32 _unistrnlen( const u16 * unistr, u32 maxlen )
{
  const u16 * pstr = NULL;
  u32 len = 0;
  if( NULL == unistr )
    return 0;

  if( 0 == maxlen )
    return 0;

  pstr = unistr;

  while( len < maxlen && *pstr != 0x0000 )
  {
    ++len;
    ++pstr;
  }
  return len;
}

int _unistrncmp( const u16 * src, const u16 * dest, u32 maxlen )
{
  if( NULL == src || NULL == dest )
  {
    if( src == dest ) return NULL;
    return (NULL == src ) ? -1 : 1;
  }

  while( _tolower(*src) == _tolower(*dest) && maxlen && *src != 0x0000 && *dest != 0x0000 )
  {
    ++src;
    ++dest;
    --maxlen;
  }
  if( 0 == maxlen ) return 0;

  return *src > *dest ? 1 : -1;
}

const u16 * _unistrchr( const u16 * str, u16 unichar )
{
  if( NULL == str )
    return NULL;

  while( *str != unichar && *str != 0x0000 )
  {
    ++str;
  }
  return str;
}

bool _uniisalnum( u8 ch )
{
  return true;
}
